using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Cz;

namespace Cz.CzHttpWebService
{
    public class CzHttpWebService : ICzHttp
    {
        public event CzEvent<HttpListenerRequest, HttpListenerResponse> handleRequest;
        
        [CzServiceField] private ICzConfig config;
        [CzServiceField] private ICzLog log;
        [CzServiceField(canNull = true)] private ICzTask taskFactory;
        
        private HttpListener listener;
        private bool debug;
        
        public void Start()
        {
            var prefix = config.GetWithDefault("http://+:8000/", "http", "prefix");
            var useTask = config.GetWithDefault(true, "http", "use_task");
            ReLoadConfig();
            config.OnChange += ReLoadConfig;
            
            listener = new HttpListener();
            listener.Prefixes.Add(prefix);
            listener.Start();
            if(useTask)
                taskFactory.CreateTask(GetContextTask);
            else
                listener.BeginGetContext(HttpDispatcher, null);
            
            log.Info("http start", $"use_task:{useTask}, url:" + prefix);
        }

        private async Task GetContextTask()
        {
            while (true)
            {
                var context = await listener.GetContextAsync();
                taskFactory.CreateTask(() => Process(context));
            }
        }
        
        private void HttpDispatcher(IAsyncResult ar)
        {
            var context = listener.EndGetContext(ar);
            listener.BeginGetContext(HttpDispatcher, null);

            Process(context);
        }

        private void Process(HttpListenerContext context)
        {
            try
            {
                var request = context.Request;
                var response = context.Response;

                if (debug)
                {
                    log.Info("CzHttpWebService", $"[{request.HttpMethod}]{request.Url}");
                }

                handleRequest?.Invoke(request, response);
                response.Close();
            }
            catch (Exception e)
            {
                log.Error("CzHttpWebService", "handleRequest error", e);
            }
        }
        
        private void ReLoadConfig()
        {
            debug = config.GetWithDefault(false, "http", "debug");
        }
    }
}